package com.base.cn.platform.os.common.utils.sms;

import com.base.cn.platform.os.common.j2cache.CustomCacheChannel;
import com.base.cn.platform.os.common.j2cache.J2CacheRegion;
import com.base.cn.platform.os.common.utils.ObjectUtils;
import com.base.cn.platform.os.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 短信发送 <br/>
 * <p>主要用于发送验证码短信</p>
 * <p>每个发送验证码的方法都有一个对应的验证方法，验证成功后会自己删除验证码缓存</p>
 * <p>每个操作，在24小时内只能发10条短信</p>
 *
 * @author s.li
 * @create 2017-07-14-15:27
 */
@Component
@Slf4j
public class SmsSendUtils {

    @Autowired
    private CustomCacheChannel customCacheChannel;

    @Value("${spring.profiles.include}")
    private   String include;

    private Logger logger = LoggerFactory.getLogger(SmsSendUtils.class);

    private Map<String,String> smsConfigMap = new HashMap<>();

    //单一操作-单个IP，24小时内最大发送量
    private int MAX_SEND_NUM = 10;
    //一天的毫秒量
    private int ONE_DAY = 1000 * 60 * 60 * 24;
    //一分钟毫秒量
    private int ONE_MINUTE = 1000 * 60;

    /*public void main(String[] args) throws Exception {
        //发送注册短信
        boolean s = sendRegCode("18911893513");
        logger.info("++++++++++++++++++++++s:" + s);
        //s  = sendBackPwdCode("18911893513");
        //logger.info("----------------------s:"+s);
        //验证注册短信
        //boolean s = validateRegCode("18911893513","951789");
        //logger.info("----------------------s:"+s);
    }*/
    //===============================================================================

    /**
     * 发送注册短信验证
     *
     * @param mobile 手机号
     * @return true发送成功，false发送失败
     * @throws Exception
     */
    public boolean sendRegCode(String mobile) throws Exception {
        Map<String, String> configMap = getSmsConfig();
        String regTemp = configMap.get("regTemp");
        return send(mobile, regTemp);
    }

    /**
     * 验证注册验证码真实性
     *
     * @param mobile 手机号
     * @param code   获取客户端的验证码
     * @return true验证成功，false验证失败
     */
    public boolean validateRegCode(String mobile, String code) {
        return  validationUniversalCode(mobile,code,"regTemp",true);
    }

    /**
     * 删除注册验证码的缓存
     * @param mobile 手机号
     */
    public void removeRegCode(String mobile){
        removeRedisCacheCode(mobile, "regTemp");
    }

    /**
     * 发送完善资料短信验证
     *
     * @param mobile 手机号
     * @return true发送成功，false发送失败
     * @throws Exception
     */
    public boolean sendUserInfoCode(String mobile) throws Exception {
        Map<String, String> configMap = getSmsConfig();
        String regTemp = configMap.get("userInfo");
        return send(mobile, regTemp);
    }

    /**
     * 验证完善资料验证码真实性
     *
     * @param mobile 手机号
     * @param code   获取客户端的验证码
     * @return true验证成功，false验证失败
     */
    public boolean validateUserInfoCode(String mobile, String code) {
        return  validationUniversalCode(mobile,code,"userInfo",false);
    }

    /**
     * 删除完善资料验证码的缓存
     * @param mobile 手机号
     */
    public void removeUserInfoCode(String mobile){
        removeRedisCacheCode(mobile, "userInfo");
    }

    /**
     * 发送找回密码短信验证
     *
     * @param mobile 手机号
     * @return true发送成功，false发送失败
     * @throws Exception
     */
    public boolean sendBackPwdCode(String mobile) throws Exception {
        Map<String, String> configMap = getSmsConfig();
        String regTemp =  configMap.get("backPwdTemp");
        return send(mobile, regTemp);
    }

    /**
     * 验证找回密码验证码真实性
     *
     * @param mobile 手机号
     * @param code   获取客户端的验证码
     * @return true验证成功，false验证失败
     */
    public boolean validateBackPwdCode(String mobile, String code) {
        return  validationUniversalCode(mobile,code,"backPwdTemp",false);
    }

    /**
     * 删除找回密码的短信验证码
     * @param mobile 手机号
     */
    public void removeBackPwdCode(String mobile){
        removeRedisCacheCode(mobile, "backPwdTemp");
    }

    /**
     * 发送绑定手机号验证码
     *
     * @param mobile 手机号
     * @return true发送成功，false发送失败
     * @throws Exception
     */
    public boolean sendBindingCode(String mobile) throws Exception {
        Map<String, String> configMap = getSmsConfig();
        String regTemp = configMap.get("bindingTemp");
        return send(mobile, regTemp);
    }

    /**
     * 验证绑定手机号验证码真实性
     *
     * @param mobile 手机号
     * @param code   获取客户端的验证码
     * @return true验证成功，false验证失败
     */
    public boolean validateBindingCode(String mobile, String code) {
        return  validationUniversalCode(mobile,code,"bindingTemp",false);
    }

    /**
     * 删除验证绑定手机号验证码缓存
     * @param mobile
     */
    public void removeBindingCode(String mobile){
        removeRedisCacheCode(mobile, "bindingTemp");
    }

    /**
     * 发送改绑定手机号验证码
     *
     * @param mobile 手机号
     * @return true发送成功，false发送失败
     * @throws Exception
     */
    public boolean sendUnBindingCode(String mobile) throws Exception {
        Map<String, String> configMap = getSmsConfig();
        String regTemp = configMap.get("unBindingTemp");
        return send(mobile, regTemp);
    }

    /**
     * 验证改绑手机号验证码真实性
     *
     * @param mobile 手机号
     * @param code   获取客户端的验证码
     * @return true验证成功，false验证失败
     */
    public boolean validateUnBindingCode(String mobile, String code) {
        return  validationUniversalCode(mobile,code,"unBindingTemp",false);
    }

    /**
     * 删除验证改绑手机号验证码
     * @param mobile 手机号
     */
    public void removeUnBindingCode(String mobile){
        removeRedisCacheCode(mobile, "unBindingTemp");
    }

    /**
     * 发送后台体验申请手机号验证码
     *
     * @param mobile 手机号
     * @return true发送成功，false发送失败
     * @throws Exception
     */
    public boolean sendTestUserCode(String mobile) throws Exception {
        Map<String, String> configMap = getSmsConfig();
        String regTemp = configMap.get("testUser");
        return send(mobile, regTemp);
    }

    /**
     * 验证后台申请体验手机号验证码真实性
     *
     * @param mobile 手机号
     * @param code   获取客户端的验证码
     * @return true验证成功，false验证失败
     */
    public boolean validateTestUserCode(String mobile, String code) {
        return  validationUniversalCode(mobile,code,"testUser",true);

    }

    public boolean sendRemindSms(String mobiles, String content) {
        Map<String, String> configMap = getSmsConfig();
        String AppKey = configMap.get("AppKey");
        String appId = configMap.get("appId");
        String appSecret = configMap.get("appSecret");
        return CSYSmsSendUtils.sendMessage(mobiles, content, AppKey, appId, appSecret);
    }

    //===================================================================================

    /**
     * 发送短信
     *
     * @param mobile 手机事情
     * @param tempId 内容模板ID
     * @return true发送成功，false发送失败
     * @throws Exception
     */
    private boolean send(String mobile, String tempId){
        Map<String, String> configMap = getSmsConfig();
        String AppKey = configMap.get("AppKey");
        String appId = configMap.get("appId");
        String appSecret = configMap.get("appSecret");

        //限制防盗刷，开始------------------
        if (!StringUtils.isMobile(mobile) || StringUtils.isEmpty(tempId)) {
            return false;
        }
        //非法发送（或过于频繁发送）
        if (!safetyVerification(appId, mobile, tempId)) {
            return false;
        }
        //请求来源
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        request.getHeader("referer");

        //限制防盗刷，结束------------------

        //-------------执行发送------开始
        //生成6位验证码
        String codeNum = StringUtils.getRandStr(6);
        logger.info("-----------------------验证码："+codeNum);
        boolean status =false;
        if(ObjectUtils.isEmpty(configMap.get("serviceName"))||StringUtils.isEmpty(configMap.get("serviceName"))||configMap.get("serviceName").equals("CSY")){
            String context = getSmsContext(tempId, codeNum);
            status = CSYSmsSendUtils.sendMessage(mobile, context, AppKey, appId, appSecret);
        }else{
            Map<String, String> context = new HashMap();
            context.put("code",codeNum);
            status = ALSmsSendUtils.aliSendMessage(mobile,context, tempId, appId, appSecret,configMap.get("sig"));
        }

        if (status) {
            //设置安全验证数据
            setSafetyData(AppKey, mobile, tempId, codeNum);
            return true;
        }
        //-------------执行发送------结束
        return false;
    }

    /**
     * 发送后台注册云服务的账号
     *
     * @param mobile 手机号
     * @return true发送成功，false发送失败
     * @throws Exception
     */
    public boolean sendVideoCloudServiceCode(String mobile) throws Exception {
        Map<String, String> configMap = getSmsConfig();
        String regTemp = configMap.get("videoCloudService");
        return send(mobile, regTemp);
    }

    /**
     * 验证注册升级短信
     *
     * @param mobile 手机号
     * @param code   获取客户端的验证码
     * @return true验证成功，false验证失败
     */
    public boolean validateVideoCloudServiceCode(String mobile, String code) {

        return  validationUniversalCode(mobile,code,"videoCloudService",false);
    }

    /**
     * 安全验证
     *
     * @param appKey
     * @param mobile
     * @param tempId
     * @return true验证通过，false验证未通过
     */
    private boolean safetyVerification(String appKey, String mobile, String tempId) {
        String commKey = getCommonKey(appKey, mobile, tempId);

        //验证上次发送时间，判断是否频繁发送（1分钟内只能发送一次）
        String timeKey = commKey + "time";
        //得到上次发送时间
        Date upTime = (Date) customCacheChannel.get(J2CacheRegion.ONE_MINUTE_REGION.getKey(), timeKey).getValue();
        if (ObjectUtils.isNotEmpty(upTime)) {
            //如果上一次发送未起过一分钟，则视为频繁发送
            if ((new Date().getTime() - upTime.getTime()) < ONE_MINUTE) {
                logger.info("+++++++++++++++++++++++++++++单一操作过于频繁发送");
                return false;
            }
        }

        //频繁发送验证通过，再验证单一操作24小时内的发送量
        String everyDayStartTimeKey = commKey + "every_day_time_start";
        Date everyDayStartTime = (Date) customCacheChannel.get(J2CacheRegion.ONE_DAY_REGION.getKey(), everyDayStartTimeKey).getValue();
        //如果有数据
        if (ObjectUtils.isNotEmpty(everyDayStartTime)) {
            //如果上一次的同一个操作第一次发送未超过24小时
            if ((new Date().getTime() - everyDayStartTime.getTime()) < ONE_DAY) {
                String numKey = commKey + "num";//发送量的Key
                Integer sendNum = (Integer) customCacheChannel.get(J2CacheRegion.ONE_DAY_REGION.getKey(), numKey).getValue();
                if (ObjectUtils.isNotEmpty(sendNum)) {
                    //如果在24小时内，单一操作量已超过最大量，则验证不通过
                    if (sendNum.intValue() >= MAX_SEND_NUM) {
                        logger.info("----------------------------单一操作24小时内发送量已达到最大量");
                        return false;
                    }
                }
            }
        }
        return true;
    }

    /**
     * 设置安全验证数据
     *
     * @param appKey 腾讯云KEY
     * @param mobile 手机号
     * @param tempId 腾讯云短信模板ID
     * @param code   验证码（用于缓存验证）
     */
    private void setSafetyData(String appKey, String mobile, String tempId, String code) {

        String commKey = getCommonKey(appKey, mobile, tempId);

        //缓存每次发送时间点，用于判断是否频繁发送（1分钟内只能发送一次）
        String timeKey = commKey + "time";
        customCacheChannel.set(J2CacheRegion.ONE_MINUTE_REGION.getKey(), timeKey, new Date());

        //设置每天第一次发送时间点，
        //如果缓存有数据则判断是否超过24小时，如果超过24小时则重新设置时间点（因为要验证24小时内发送量）
        String everyDayStartTimeKey = commKey + "every_day_time_start";//缓存每天第一次发送时间
        Date everyDayStartTime = (Date) customCacheChannel.get(J2CacheRegion.ONE_DAY_REGION.getKey(), everyDayStartTimeKey).getValue();
        if (ObjectUtils.isNotEmpty(everyDayStartTime)) {
            if ((new Date().getTime() - everyDayStartTime.getTime()) >= ONE_DAY) {
                customCacheChannel.set(J2CacheRegion.ONE_DAY_REGION.getKey(), everyDayStartTimeKey, new Date());
            }
        } else {
            customCacheChannel.set(J2CacheRegion.ONE_DAY_REGION.getKey(), everyDayStartTimeKey, new Date());
        }

        //设置已发送的量，每天同一个操作发送短信量有限制
        String numKey = commKey + "num";//发送量的Key
        Integer sendNum = (Integer) customCacheChannel.get(J2CacheRegion.ONE_DAY_REGION.getKey(), numKey).getValue();
        if (!ObjectUtils.isNotEmpty(sendNum)) {
            sendNum = 1;
        } else {
            sendNum = sendNum.intValue() + 1;
        }
        logger.info("------------------mobile send num :" + sendNum);
        customCacheChannel.set(J2CacheRegion.ONE_DAY_REGION.getKey(), numKey, sendNum);
        //缓存验证码
        customCacheChannel.set(J2CacheRegion.THIRD_MINUTE_REGION.getKey(), commKey, code);
    }

    /**
     * 获取缓存中的验证码
     *
     * @param mobile
     * @param tempKey
     * @return
     */
    private String getRedisCacheCode(String mobile, String tempKey) {
        Map<String, String> configMap = getSmsConfig();
        String AppKey = configMap.get("AppKey");
        String regTemp = configMap.get(tempKey);
        String commKey = getCommonKey(AppKey, mobile, regTemp);
        String _cdoe = customCacheChannel.get(J2CacheRegion.THIRD_MINUTE_REGION.getKey(), commKey).asString();
        return _cdoe;
    }

    /**
     * 删除验证缓存
     *
     * @param mobile
     * @param tempKey
     */
    private void removeRedisCacheCode(String mobile, String tempKey) {
        Map<String, String> configMap = getSmsConfig();
        String AppKey = configMap.get("AppKey");
        String regTemp = configMap.get(tempKey);
        String commKey = getCommonKey(AppKey, mobile, regTemp);
        customCacheChannel.evict(J2CacheRegion.THIRD_MINUTE_REGION.getKey(),commKey);
    }

    /**
     * 获取共用KEY
     *
     * @param appKey
     * @param mobile
     * @param tempId
     * @return
     */
    private String getCommonKey(String appKey, String mobile, String tempId) {
        return appKey + "_" + mobile + "_" + tempId;
    }

    /**
     * 设置配置信息
     * 设置配置信息
     * @param configMap
     */
    public void setSmsConfig(Map<String,String> configMap){
        this.smsConfigMap = configMap;
    }

    /**
     * 获取短信配置信息
     *
     * @return Map<String   ,   String>
     */
    private Map<String, String> getSmsConfig() {
        this.smsConfigMap.put("regTemp", "1001");//注册模板
        this.smsConfigMap.put("backPwdTemp", "2001");//找回密码模板
        this.smsConfigMap.put("bindingTemp", "3001");//绑定手机号模板
        this.smsConfigMap.put("unBindingTemp", "4001");//换绑定手机号模板
        this.smsConfigMap.put("testUser", "5001");//申请体验用户模板
        this.smsConfigMap.put("agentCodeTemp", "6001");//申请开通分销商模板
        this.smsConfigMap.put("agentCode", "7001");//申请开通分销商模板
        this.smsConfigMap.put("userInfo", "8001");//完善资料验证模板
        this.smsConfigMap.put("videoCloudService", "9001");//开通升级云视频
        return this.smsConfigMap;
    }

    /**
     * 通过模板ID获取短信内容
     *
     * @param tempId  模板ID
     * @param codeNum 验证码
     * @return 模板内容
     */
    private String getSmsContext(String tempId, String codeNum) {
        switch (tempId) {
            case "1001":
                return "您的注册验证码是" + codeNum + "，请在30分钟内输入，如非本人请忽略本短信。";
            case "2001":
                return "您的找回密码的验证码是" + codeNum + "，请在30分钟内输入，如非本人请忽略本短信。";
            case "3001":
                return "您的绑定手机号的验证码是" + codeNum + "，请在30分钟内输入，如非本人请忽略本短信。";
            case "4001":
                return "您的改绑手机号的验证码是" + codeNum + "，请在30分钟内输入，如非本人请忽略本短信。";
            case "5001":
                return "体验账号申请验证码是" + codeNum + ", 请在30分钟内输入，如非本人请忽略。";
            case "6001":
                return "您申请成为平台推广员的手机验证码是" + codeNum + "，请在30分钟内输入，如非本人请忽略。";
            case "7001":
                return "您申请的分销商已通过审核，平台中的分销商权限可以正常使用了，感谢您的支持,如非本人请忽略。";
            case "8001":
                return "您完善绑定的验证码是" + codeNum + "，请在30分钟内输入，如果非本人请忽略。";
            case "9001":
                return "您的开通升级云视频的短信验证码是"+codeNum+"，请在5分钟内操作完成，如非本人请忽略本短信信息。";
            default:
                return null;
        }
    }


    /**
     * 验证验证码真实性
     *
     * @param mobile 手机号
     * @param code   获取客户端的验证码
     * @param tempKey 模板key
     * @param del 是否删除缓存
     * @return true验证成功，false验证失败
     */
    public boolean validationUniversalCode(String mobile, String code,String tempKey,boolean del) {
        if(StringUtils.isNotEmpty(include)){
            String[] split = include.split("-");
            if(split[2].equals("dev")||split[2].equals("test")){
                if(code.equals("268")){
                    return true;
                }
            }
        }
        String _cdoe = getRedisCacheCode(mobile, tempKey);
        if (!code.equals(_cdoe)) {
            return false;
        }
        if(del){
            removeRedisCacheCode(mobile, tempKey);
        }
        return true;
    }
}
